﻿using Basic.RPC.Abstract;
using Hprose.RPC;
using Hprose.RPC.Plugins.Limiter;
using System.Collections.Concurrent;

namespace Basic.RPC.Impl;

/// <summary>
/// Rpc客户端
/// </summary>
internal class HproseRpcClient : IRpcClient
{
    private bool IsInitialize;
    private List<RpcClientService> Services;
    private IDictionary<string, IDictionary<string, string>> ServiceDict;

    private ConcurrentDictionary<Guid, Client> TypeDict;
    private ConcurrentDictionary<string, Client> ClientDict;

    public HproseRpcClient()
    {
        //Hprose.RPC.AspNetCore.AspNetCoreHttpHandler
    }

    public HproseRpcClient(List<RpcClientService> services, IDictionary<string, IDictionary<string, string>> serviceDict)
    {
        Services = services;
        ServiceDict = serviceDict;
    }

    /// <summary>
    /// 初始化Rpc客户端
    /// </summary>
    public void Initialize()
    {
        if (IsInitialize == true)
            return;

        foreach (var rpcService in Services)
        {
            string rpcServiceName = rpcService.ServiceName;
            var rpcArray = ServiceDict.Values.Where(s => s.TryGetValue("Name", out string serviceName) && string.Equals(rpcServiceName, serviceName)).ToArray();
            if (rpcArray.Length > 0)
            {
                List<string> urls = new List<string>();
                rpcService.RPCAddresses = rpcArray.Where(s => s.ContainsKey("RpcPort")).Select(s => $"tcp://{s["IP"]}:{s["RpcPort"]}").ToArray();
            }
        }

        TypeDict = new ConcurrentDictionary<Guid, Client>();
        ClientDict = new ConcurrentDictionary<string, Client>();

        foreach (var item in Services)
        {
            var client = new Client(item.RPCAddresses);
            //client.Use(Oneway.Handler);
            client.Use(new ConcurrentLimiter(32).Handler).Use(new RateLimiter(2000).InvokeHandler);

            ClientDict.TryAdd(item.ServiceName, client);

            var types = item.InterfaceTypes;
            foreach (var type in types)
                TypeDict.TryAdd(type.GUID, client);
        }

        IsInitialize = true;
    }

    /// <summary>
    /// 获取RPC服务
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetService<T>() where T : class
    {
        Type type = typeof(T);
        if (TypeDict.TryGetValue(type.GUID, out var client))
        {
            string name = typeof(T).Name;
            return client.UseService<T>(name);
        }
        return null;
    }

    #region Dispose
    private bool disposedValue;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: 释放托管状态(托管对象)
            }

            // TODO: 释放未托管的资源(未托管的对象)并重写终结器
            // TODO: 将大型字段设置为 null
            disposedValue = true;
        }
    }

    public void Dispose()
    {
        // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
    #endregion

}